//
// Project werewolf: game_director.h
// Created by alfielin on 2021/11/14.
//

#pragma once

#include "util/rng.cpp"
#include "game_room.cpp"

namespace nz {
namespace werewolf {

class RoomManager {

ENABLE_SINGLETON(RoomManager);

private:
    std::unordered_map<int, std::shared_ptr<GameRoom>> roomid2room;
    std::mutex create_room_mutex;

    RoomManager () = default;

public:

    int create_room (const std::string &userid, const GameConfig &config) {
        int roomid;
        { // ======================== Critical Area ========================
            std::unique_lock<std::mutex> lck(create_room_mutex);
            RNG rng;
            roomid = rng.rand_int(
                    1234, 98765, [this] (int id) { return roomid2room.count(id) == 0; });
            roomid2room[roomid] = nullptr;
        }
        std::shared_ptr<GameRoom> room_ptr = std::make_shared<GameRoom>(roomid, userid, config);
        roomid2room.at(roomid) = room_ptr;
        room_ptr->join(userid);
        LOOP->setTimeout(3 * 3600 * 1000, [roomid, this] (auto timerid) {
            roomid2room.erase(roomid);
            LOGGER->info("Room {} automatically destroyed after 3h", roomid);
        });
        return roomid;
    }

    void exit_room (const std::string &userid) {
        auto room = get_room_by_userid(userid);
        if (!room) { return; }
        if (room->get_ownerid() == userid) {
            roomid2room.erase(room->get_roomid());
        } else {
            room->exit(userid);
        }
    }

    void start_game (const int &roomid) {
        roomid2room.at(roomid)->start_game();
    }

    std::shared_ptr<GameRoom> get_room (int roomid) {
        if (!roomid2room.count(roomid)) { return nullptr; }
        return roomid2room.at(roomid);
    }

    std::shared_ptr<GameRoom> get_room_by_userid (const std::string &userid) {
        return get_room(GameRoom::get_roomid_by_userid(userid));
    }
};

}
}

